home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / BOOTPD.C < prev    next >
Encoding:
C/C++ Source or Header  |  1997-07-30  |  11.8 KB  |  487 lines

  1. /*
  2.  * Center for Information Technology Integration
  3.  *           The University of Michigan
  4.  *                    Ann Arbor
  5.  *
  6.  * Dedicated to the public domain.
  7.  * Send questions to info@citi.umich.edu
  8.  *
  9.  * BOOTP is documented in RFC 951 and RFC 1048
  10.  * Delinted, ANSIfied and reformatted - 5/30/91 P. Karn
  11.  */
  12.  
  13.  
  14. /*
  15.  * BOOTP (bootstrap protocol) server daemon.
  16.  *
  17.  */
  18.  
  19.  
  20. #include "global.h"
  21. #ifdef BOOTPSERVER
  22. #include <sys/stat.h>
  23. #include <time.h>
  24. #include "bootp.h"
  25. #include "iface.h"
  26. #include "bootpd.h"
  27. #include "udp.h"
  28.  
  29. #if !defined(_lint)
  30. static char rcsid[] OPTIONAL = "$Id: bootpd.c,v 1.14 1997/07/31 00:44:20 root Exp root $";
  31. #endif
  32.  
  33. void bootpd (struct iface *iface, struct udp_cb *sock, int16 cnt);    /*lint !e15 */
  34.  
  35. struct udp_cb *Bootpd_cb = NULLUDP;
  36.  
  37. char homedir[64] = "";        /* bootfile homedirectory */
  38. char defaultboot[64] = "";    /* default file to boot */
  39.  
  40. struct host hosts[MHOSTS + 1];
  41. int Nhosts = 0;            /* current number of hosts */
  42.  
  43. uint32 bp_DefaultDomainNS[BP_MAXDNS] = { 0 };
  44.  
  45. const char *ArpNames[] =
  46. {
  47.     "Netrom",
  48.     "Ethernet",
  49.     "AX25",
  50.     "Pronet",
  51.     "Chaos",
  52.     "IEEE 802",
  53.     "ArcNet",
  54.     "AppleTalk"
  55. };
  56.  
  57.  
  58. /* Routine declarations */
  59. static int bootpd_recv (struct udp_cb *sock, struct bootp *bootp);
  60. static void sendreply (struct bootp *bp, struct iface *iface);
  61. static void vend_fill (char *vend, struct iface *iface, struct host *hp);
  62. static void bootpd_request (struct bootp *rq, struct iface *iface);
  63. #if 0
  64. static void vend_print (char *vend);
  65. #endif
  66.  
  67.  
  68. /* The bootp server. */
  69. void
  70. bootpd (struct iface *iface, struct udp_cb *sock, int16 cnt OPTIONAL)
  71. {
  72. struct bootp bp_packet;
  73.  
  74.     while (bootpd_recv (sock, &bp_packet) != -1) {
  75.  
  76.         if (readtab () == -1)    /* maybe re-read bootptab */
  77.             return;
  78.  
  79.         switch (uchar (bp_packet.op)) {
  80.             case BOOTREQUEST:
  81.                 bootpd_request (&bp_packet, iface);
  82.                 break;
  83.             case BOOTREPLY:
  84.             default:
  85.                 /* Replies are not forwarded, left to the gateway */
  86.                 break;
  87.         }
  88.  
  89.     }
  90.  
  91. }
  92.  
  93.  
  94.  
  95. /* A packet has been received, read it into a bootp structure. */
  96. static int
  97. bootpd_recv (struct udp_cb *sock, struct bootp *bootp)
  98. {
  99. struct socket fsock;
  100. struct mbuf *bp;
  101. int len;
  102.  
  103.     /* receive the packet */
  104.     len = recv_udp (sock, &fsock, &bp);
  105.     if (len == -1)
  106.         return -1;
  107.  
  108.  
  109.     /* check length of packet */
  110.     if (len < (int) sizeof (struct bootp)) {
  111.         bootp->op = 0;
  112.         free_p (bp);
  113.         return -1;
  114.     }
  115.     /* parse the packet */
  116.     (void) pullup (&bp, (unsigned char *) bootp, sizeof (struct bootp));
  117.  
  118.     free_p (bp);
  119.  
  120.     if (bootp->op != BOOTREPLY && bootp->op != BOOTREQUEST) {
  121.         bootp->op = 0;
  122.         return -1;
  123.     }
  124.     bootp->ciaddr.s_addr = (unsigned long) get32 ((char *) &(bootp->ciaddr));
  125.     bootp->giaddr.s_addr = (unsigned long) get32 ((char *) &(bootp->giaddr));
  126.     return 0;
  127. }
  128.  
  129.  
  130.  
  131. /*
  132.  * Process BOOTREQUEST packet.
  133.  *
  134.  * (Note, this version of the bootp.c server never forwards
  135.  * the request to another server.  In our environment the
  136.  * stand-alone gateways perform that function.)
  137.  *
  138.  * (Also this version does not interpret the hostname field of
  139.  * the request packet;  it COULD do a name->address lookup and
  140.  * forward the request there.)
  141.  */
  142.  
  143. static void
  144. bootpd_request (struct bootp *rq, struct iface *iface)
  145. {
  146. struct bootp *rp;
  147. char path[64], file[64];
  148. struct host *hp;
  149. int n;
  150. time_t tloc;
  151. uint32 ipaddr;
  152. struct arp_type *at;
  153.  
  154.     (void) time (&tloc);
  155.     bp_log ("\nBootpd request packet received %s", ctime (&tloc));
  156.     /* Forwarding not done here. */
  157.     if (rq->giaddr.s_addr) {
  158.         bp_log ("     Dropped, giaddr specifies to be forwarded;\n");
  159.         return;
  160.     }
  161.     /* Is a specific host requested? */
  162.     if ((strlen (rq->sname) != 0) && (strcmp (Hostname, rq->sname) != 0)) {
  163.         bp_log ("     Dropped, sname specifies server '%s'\n", rq->sname);
  164.         return;
  165.     }
  166.     /* allocate the reply */
  167.     rp = (struct bootp *) callocw (1, sizeof (struct bootp));
  168.  
  169.     if (!rp) {
  170.         bp_log ("     Dropped, insufficient memory '%s'\n", rq->sname);
  171.         return;
  172.     }
  173.     /* copy for construction */
  174.     memcpy (rp, rq, sizeof (struct bootp) - sizeof (rp->vend));
  175.  
  176.     rp->op = BOOTREPLY;
  177.  
  178.     hp = NULLHOST;
  179.  
  180.  
  181.     /* If the client doesn't know it's ip address, find one. */
  182.     if (rq->ciaddr.s_addr == 0) {
  183.         /*
  184.          * client doesn't know his IP address,
  185.          * search by hardware address.
  186.          */
  187.         at = &Arp_type[(int) rq->htype];
  188.         bp_log ("     Resolved by %s addr %s\n", ArpNames[(int) rq->htype],
  189.             (*at->format) (bp_ascii, rq->chaddr));
  190.  
  191.         for (hp = &hosts[0], n = 0; n < Nhosts; n++, hp++)
  192.             if ((uchar (rq->htype) == hp->htype)
  193.                 && (strncmp (rq->chaddr, hp->haddr, (size_t) (int) rq->hlen) == 0))
  194.                 break;
  195.  
  196.         /* If the client wasn't found, assign an IP address */
  197.         if (n == Nhosts) {
  198.  
  199.             hp = NULLHOST;
  200.             if (da_assign (iface, rq->chaddr, &ipaddr) != 0) {
  201.                 free (rp);
  202.                 bp_log ("     No dynamic addresses available.\n");
  203.                 return;
  204.             } else {
  205.                 (void) put32 ((unsigned char *) &(rp->yiaddr), ipaddr);
  206.                 bp_log ("     Dynamic address assigned: %s\n", inet_ntoa (ipaddr));
  207.             }
  208.         } else {
  209.             bp_log ("     Static address assigned: %s\n", inet_ntoa (hp->iaddr.s_addr));
  210.             (void) put32 ((unsigned char *) &(rp->yiaddr), hp->iaddr.s_addr);
  211.         }
  212.  
  213.     } else {
  214.         /* search by IP address */
  215.         bp_log ("     Resolve by IP addr %s\n", inet_ntoa (rq->ciaddr.s_addr));
  216.         for (hp = &hosts[0], n = 0; n < Nhosts; n++, hp++)
  217.             if (rq->ciaddr.s_addr == hp->iaddr.s_addr)
  218.                 break;
  219.         if (n == Nhosts) {
  220.             hp = NULLHOST;
  221.             bp_log ("     Host not found, default values used.\n");
  222.         } else
  223.             bp_log ("     Lookup successful.\n");
  224.         (void) put32 ((unsigned char *) &(rp->ciaddr), (uint32) rq->ciaddr.s_addr);
  225.     }
  226.  
  227.     (void) put32 ((unsigned char *) &(rp->siaddr), iface->addr);
  228.  
  229.     /* Determine the bootp file */
  230.     file[0] = 0;
  231.     if (rq->file[0] == 0) {    /* if client didn't specify file */
  232.         /* Use the host record file, else the default file */
  233.         if ((hp == NULLHOST) || (hp->bootfile[0] == 0))
  234.             strcpy (file, defaultboot);
  235.         else
  236.             strcpy (file, hp->bootfile);
  237.     } else     /* use client specified file */
  238.         strcpy (file, rq->file);
  239.  
  240.     /* If a file is specified, specify the path to the bootp file */
  241.     path[0] = 0;
  242.     if ((*homedir != 0) && (*file != 0)) {
  243.         strcpy (path, homedir);
  244.         strcat (path, "/");
  245.     }
  246.     if (file[0] == '/')    /* if absolute pathname */
  247.         strcpy (path, file);
  248.     else
  249.         strcat (path, file);
  250.  
  251.     /* No files are provided here, just return a path. */
  252.     strcpy (rp->file, path);
  253.  
  254.     /* Fill in the vendor information */
  255.     vend_fill (rp->vend, iface, hp);
  256.  
  257.     sendreply (rp, iface);
  258.     free (rp);
  259.  
  260. }
  261.  
  262.  
  263.  
  264. #if 0
  265. static void bootp_print_packet (struct bootp *bp);
  266.  
  267. /* Print the bootp structure. */
  268. static void
  269. bootp_print_packet (struct bootp *bp)
  270. {
  271.     bp_log ("Packet op code........................%d\n", bp->op);
  272.     bp_log ("hardware address type.................%d\n", bp->htype);
  273.     bp_log ("hardware address length...............%d\n", bp->hlen);
  274.     bp_log ("client sets to zero...................%d\n", bp->hops);
  275.     bp_log ("transaction ID........................%ld\n", bp->xid);
  276.     bp_log ("seconds elapsed since client booted...%d\n", bp->secs);
  277.     bp_log ("unused................................%d\n", bp->unused);
  278.     bp_log ("Client IP address, if known...........%s\n",
  279.         inet_ntoa (bp->ciaddr.s_addr));
  280.     bp_log ("Server supplied IP address............%s\n",
  281.         inet_ntoa (bp->yiaddr.s_addr));
  282.     bp_log ("Server IP address.....................%s\n",
  283.         inet_ntoa (bp->siaddr.s_addr));
  284.     bp_log ("Gateway IP address....................%s\n",
  285.         inet_ntoa (bp->giaddr.s_addr));
  286.     bp_log ("Client hardware address...............%x:%x:%x:%x:%x:%x\n",
  287.         bp->chaddr[0], bp->chaddr[1], bp->chaddr[2],
  288.         bp->chaddr[3], bp->chaddr[4], bp->chaddr[5]);
  289.     bp_log ("Server host name......................'%s'\n", bp->sname);
  290.     bp_log ("Boot file name........................'%s'\n", bp->file);
  291.  
  292.     vend_print (bp->vend);
  293. }
  294.  
  295.  
  296.  
  297. static void
  298. vend_print (char *vend)
  299. {
  300. unsigned char ch;
  301. int size;
  302. char *start;
  303. uint32 *ipaddr;
  304. int i;
  305.  
  306.     start = vend;
  307.  
  308.     bp_log ("Magic Cookie..........................x%02x%02x%02x%02x\n",
  309.         (int) vend[0], (int) vend[1], (int) vend[2], (int) vend[3]);
  310.     vend = vend + 4;
  311.  
  312.     while (((ch = uchar (*vend++)) != BOOTP_END) && (vend - start <= 64))
  313.         switch (ch) {
  314.  
  315.             case BOOTP_PAD:    /* They're just padding */
  316.                 continue;
  317.             case BOOTP_SUBNET:    /* fixed length, 4 octets */
  318.                 size = (int) *vend++;
  319.                 ipaddr = (uint32 *) vend;
  320.                 bp_log ("Vend Subnet...........................%s\n", inet_ntoa (*ipaddr));
  321.                 vend += size;
  322.                 break;
  323.             case BOOTP_HOSTNAME:
  324.                 size = (int) *vend++;
  325.                 bp_log ("Vend Hostname.........................%s\n", vend);
  326.                 vend += size;
  327.                 break;
  328.             case BOOTP_DNS:
  329.                 size = (int) *vend++;
  330.                 for (i = 0; i < (size / 4); i++) {
  331.                     ipaddr = (uint32 *) vend;
  332.                     bp_log ("Vend DomainNS.........................%s\n",
  333.                         inet_ntoa (*ipaddr));
  334.                     vend += 4;
  335.                 }
  336.                 break;
  337.             case BOOTP_GATEWAY:
  338.                 size = (int) *vend++;
  339.                 for (i = 0; i < (size / 4); i++) {
  340.                     ipaddr = (uint32 *) vend;
  341.                     bp_log ("Vend Gateway..........................%s\n",
  342.                         inet_ntoa (*ipaddr));
  343.                     vend += 4;
  344.                 }
  345.                 break;
  346.  
  347.  
  348.             default:    /* variable field we don't know about */
  349.                 size = *vend++;
  350.                 vend += size;
  351.                 break;
  352.         }
  353.  
  354. }
  355. #endif
  356.  
  357.  
  358.  
  359. static unsigned char cookie[5] = { 99, 130, 83, 99, 0 };
  360.  
  361.  
  362.  
  363. static void
  364. vend_fill (char *vend, struct iface *iface, struct host *hp)
  365. {
  366. int len;
  367. int mod;
  368. int i;
  369. char *sizep;
  370.  
  371.     /* Magic cookie */
  372.     strcpy (vend, (char *) cookie);
  373.     vend += 4;
  374.  
  375.     /* Send the iface subnet */
  376.     /* Pad so number falls on word boundry */
  377.  
  378.     vend++;
  379.     vend++;
  380.  
  381.     *vend = BOOTP_SUBNET;
  382.     vend++;
  383.     *vend = 4;
  384.     vend++;
  385.     (void) put32 ((unsigned char *) vend, iface->netmask);
  386.     vend += 4;
  387.  
  388.  
  389.     /* Send the DNS */
  390.     if (bp_DefaultDomainNS[0] != 0) {
  391.         /* Pad for allignment */
  392.         vend++;
  393.         vend++;
  394.  
  395.         *vend = BOOTP_DNS;
  396.         vend++;
  397.         sizep = vend;
  398.         vend++;
  399.         for (i = 0; (i < BP_MAXDNS) && (bp_DefaultDomainNS[i] != 0); i++) {
  400.             (void) put32 ((unsigned char *) vend, (uint32) bp_DefaultDomainNS[i]);
  401.             *sizep = *sizep + 4;
  402.             vend += 4;
  403.         }
  404.     }
  405.     /* Send the default gateway */
  406.     if (R_default.iface == iface) {
  407.         vend++;
  408.         vend++;
  409.  
  410.         *vend = BOOTP_GATEWAY;
  411.         vend++;
  412.         *vend = 4;
  413.         vend++;
  414.         (void) put32 ((unsigned char *) vend, R_default.gateway);
  415.         vend += 4;
  416.     }
  417.     /* Send the hostname */
  418.     if (hp != NULLHOST) {
  419.         /* Pad so name begins on a word boundry */
  420.         vend++;
  421.         vend++;
  422.  
  423.         *vend = BOOTP_HOSTNAME;
  424.         vend++;
  425.         *vend = (char) (len = (int) strlen (hp->name) + 1);
  426.         vend++;
  427.         strcpy (vend, hp->name);
  428.         vend += len;
  429.  
  430.         /* Pad to a word. */
  431.         mod = 4 - (len % 4);
  432.         for (i = 0; i < mod; i++) {
  433.             *vend = BOOTP_PAD;
  434.             vend++;
  435.         }
  436.     }
  437.     /* Mark the end of the data */
  438.     *vend = (char) BOOTP_END;
  439. }
  440.  
  441.  
  442.  
  443. /*
  444.  * Send a reply packet to the client.  'forward' flag is set if we are
  445.  * not the originator of this reply packet.
  446.  */
  447. static void
  448. sendreply (struct bootp *bp, struct iface *iface)
  449. {
  450. struct mbuf *buf;
  451. uint32 faddr;
  452. int16 length;
  453. unsigned char *cp;
  454.  
  455.     /*
  456.      * If the client IP address is specified, use that
  457.      * else if gateway IP address is specified, use that
  458.      * else make a temporary arp cache entry for the client's NEW
  459.      * IP/hardware address and use that.
  460.      */
  461.     if (bp->ciaddr.s_addr)
  462.         faddr = get32 ((char *) &(bp->ciaddr));
  463.     else {
  464.         faddr = get32 ((char *) &(bp->yiaddr));
  465.         (void) arp_add (faddr, (int16) (int) bp->htype, bp->chaddr, 0, iface);
  466.     }
  467.  
  468.     if ((buf = qdata ((unsigned char *) bp, sizeof (struct bootp))) == NULLBUF)
  469.               return;
  470.  
  471.     if ((buf = pushdown (buf, UDPHDR)) == NULLBUF)
  472.         return;
  473.  
  474.     length = sizeof (struct bootp) + UDPHDR;
  475.  
  476.     cp = buf->data;
  477.     cp = put16 (cp, IPPORT_BOOTPS);    /* Source */
  478.     cp = put16 (cp, IPPORT_BOOTPC);    /* Dest */
  479.     cp = put16 (cp, length);
  480.     *cp++ = 0;
  481.     *cp = 0;
  482.  
  483.     (void) ip_send (iface->addr, faddr, UDP_PTCL, 0, 0, buf, length, 0, 0);
  484. }
  485.  
  486. #endif    /* BOOTPSERVER */
  487.